package com.gmail.dengtao.joe.game.server.client.handler;

import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.Map.Entry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.gmail.dengtao.joe.commons.util.ByteUtils;
import com.gmail.dengtao.joe.commons.util.NumberUtils;
import com.gmail.dengtao.joe.game.model.Player;
import com.gmail.dengtao.joe.game.server.Constant;
import com.gmail.dengtao.joe.game.server.GameCache;
import com.gmail.dengtao.joe.game.transport.filter.DataFilter;
import com.gmail.dengtao.joe.group.channel.Channel;
import com.gmail.dengtao.joe.transport.handler.HandlerAdapter;
import com.gmail.dengtao.joe.transport.session.IdleStatus;
import com.gmail.dengtao.joe.transport.session.Session;

public class GameClientHandler extends HandlerAdapter {

	private static final Logger LOGGER = LoggerFactory.getLogger(GameClientHandler.class);

	private Channel channel;
	private static int MAX_X = 329;
	private static int MAX_Y = 234;
	
	public GameClientHandler(Channel channel) {
		this.channel = channel;
	}

	@Override
	public void sessionOpened(Session session) throws Exception {
		LOGGER.info("[GAMESERVER][ACCEPTOR][CLIENT][CONNECTED][SESSION:" + session + "]");
	}

	@Override
	public void sessionIdle(Session session, IdleStatus status)
			throws Exception {
		LOGGER.info("[GAMESERVER][ACCEPTOR][CLIENT][IDLE][STATUS:" + status + "][SESSION:" + session + "]");
		session.close();
	}

	@Override
	public void dataReceived(Session session, Object data) throws Exception {
		String message = new String((byte[])data);
		String[] params = message.split("\\|");
		if (Constant.CLIENT_PLAYER_LOGIN.equals(params[0])) {	// player login
			playerLogin(session, params);
		} else {	// need player login
			if (GameCache.playersCache.containsKey(session)) {
				Player player = GameCache.playersCache.get(session);
				if (Constant.CLIENT_PLAYER_MOVE.equals(params[0])) {	// player move
					playerMove(player, session, params);
				} else {
					
				}
			} else {
				LOGGER.warn("[GAMESERVER][ACCEPTOR][CLIENT][NOT LOGIN][DISCONNECT...][SESSION:" + session + "]");
				session.close();
			}
		}
		//LOGGER.info("[GAMESERVER][ACCEPTOR][CLIENT][RECEIVED][" + message + "][SESSION:" + session + "]");
	}

	@Override
	public void dataNotSent(Session session, Object data) throws Exception {
		LOGGER.info("[GAMESERVER][ACCEPTOR][CLIENT][NOTSENT][" + new String((byte[])data) + "][SESSION:" + session + "]");
	}

	@Override
	public void dataSent(Session session, Object data) throws Exception {
		LOGGER.info("[GAMESERVER][ACCEPTOR][CLIENT][SENT][" + new String((byte[])data) + "][SESSION:" + session + "]");
	}

	@Override
	public void sessionClosed(Session session) throws Exception {
		LOGGER.info("[GAMESERVER][ACCEPTOR][CLIENT][DISCONNECTED][SESSION:" + session + "]");
		if (GameCache.playersCache.containsKey(session)) {
			Player player = GameCache.playersCache.get(session);
			broadcast(session, packetData(Constant.NOTIFY_PLAYER_LOGOFF, player.getName()));
			channel.broadcast(Constant.NOTIFY_PLAYER_LOGOFF + "|" + player.getName());
			GameCache.players.remove(player.getName());
			GameCache.playersCache.remove(session);
			GameCache.sessions.remove(player);
		}
	}

	@Override
	public void exceptionCaught(Session session, Throwable cause) {
		//LOGGER.info("[GAMESERVER][ACCEPTOR][CLIENT][EXCEPTION][SESSION:" + session + "]", cause);
	}

	// 完成封包
	public byte[] packetData(String type, String data) {
		byte[] bts = (type + "|" + data).getBytes();
		int length = 0;
		length = ByteUtils.sizeOf(DataFilter.START_IDENTIFIER, length, bts, DataFilter.END_IDENTIFIER);
		ByteBuffer buffer = ByteBuffer.allocate(length);
		buffer.put(DataFilter.START_IDENTIFIER);	// Start Symbol
		buffer.putInt(length);						// Length
		buffer.put(bts);							// data
		buffer.put(DataFilter.END_IDENTIFIER);		// End Symbol
		buffer.flip();
		byte[] dst = new byte[length];
		buffer.get(dst);
		return dst;
	}
	
	// 处理玩家登陆
	private void playerLogin(Session session, String[] params) {
		Player player = new Player();
		player.setName(params[1]);
		player.setShape(NumberUtils.toInt(params[2]));
		player.setColor(params[3]);
		if (GameCache.players.containsKey(player.getName())) {
			Player cache = GameCache.players.get(player.getName());
			
			player.setX(cache.getX());
			player.setY(cache.getY());

			// 通知下线
			Session player_session = GameCache.sessions.get(player);
			if (player_session != null) {
				LOGGER.info("[GAMESERVER][ACCEPTOR][" + player.getName() + "][LOGOFF]");
				player_session.send(packetData(Constant.CLIENT_PLAYER_LOGIN_OFF, ""));
				GameCache.playersCache.remove(player_session);
			}
		} else {
			int x = (int)(Math.random() * MAX_X);
			int y = (int)(Math.random() * MAX_Y);
			player.setX(x);
			player.setY(y);
		}

		// 更新Session
		GameCache.players.put(player.getName(), player);
		GameCache.sessions.put(player, session);
		GameCache.playersCache.put(session, player);
		
		session.send(packetData(Constant.CLIENT_PLAYER_LOGIN_ACK, player.getX() + "|" + player.getY()));
		pushPlayers(session, player.getName());
		
		broadcast(session, packetData(Constant.NOTIFY_PLAYER_LOGIN, player.getName() + "|" + player.getShape() + "|" + player.getColor() + "|" + player.getX() + "|" + player.getY()));
		channel.broadcast(Constant.NOTIFY_PLAYER_LOGIN + "|" + player.getName() + "|" + player.getShape() + "|" + player.getColor() + "|" + player.getX() + "|" + player.getY());
		LOGGER.info("[GAMESERVER][ACCEPTOR][" + player.getName() + "][LOGIN][Pos:" + player.getX() + ", " + player.getY() + "]");
	}
	
	// 推送当前玩家列表
	private void pushPlayers(Session session, String except) {
		// local players
		Iterator<Entry<String, Player>> iter = GameCache.players.entrySet().iterator();
		boolean check = true;
		for ( ; iter.hasNext(); ) {
			Entry<String, Player> entry = iter.next();
			Player player = entry.getValue();
			if (except != null && check) {
				if (player.getName().equals(except)) {
					check = false;
					continue;
				}
			}
			session.send(packetData(Constant.PUSH_PLAYER_LIST, player.getName() + "|" + player.getShape() + "|" + player.getColor() + "|" + player.getX() + "|" + player.getY()));
		}
		
		// remote players
		Iterator<Entry<String, Player>> iter_ = GameCache.remotePlayers.entrySet().iterator();
		for ( ; iter_.hasNext(); ) {
			Entry<String, Player> entry = iter_.next();
			Player player = entry.getValue();
			session.send(packetData(Constant.PUSH_PLAYER_LIST, player.getName() + "|" + player.getShape() + "|" + player.getColor() + "|" + player.getX() + "|" + player.getY()));
		}
	}

	// 玩家移动
	private void playerMove(Player player, Session session, String[] params) {
		int x = NumberUtils.toInt(params[1]);
		int y = NumberUtils.toInt(params[2]);
		if (player.getX() != x || player.getY() != y) {
			LOGGER.warn("[GAMESERVER][ACCEPTOR][" + player.getName() + "][MOVE][(" + player.getX() + ", " + player.getY() + ") => (" + x + ", " + y + ")]");
			player.setX(x);
			player.setY(y);
			broadcast(session, packetData(Constant.NOTIFY_PLAYER_MOVE, player.getName() + "|" + player.getShape() + "|" + player.getColor() + "|" + player.getX() + "|" + player.getY()));
			channel.broadcast(Constant.NOTIFY_PLAYER_MOVE + "|" + player.getName() + "|" + player.getShape() + "|" + player.getColor() + "|" + player.getX() + "|" + player.getY());
		} else {
			LOGGER.warn("[GAMESERVER][ACCEPTOR][" + player.getName() + "][MOVE][INGORE]");
		}
	}
	
	// 广播通知客户端
	public void broadcast(Session except, byte[] data) {
		Iterator<Entry<Session, Player>> iter = GameCache.playersCache.entrySet().iterator();
		boolean check = true;
		if (except == null) {
			check = false;
		}
		for ( ; iter.hasNext(); ) {
			Entry<Session, Player> entry = iter.next();
			Session session = entry.getKey();
			if (check) {
				if (session.equals(except)) {
					check = false;
					continue;
				}
			}
			session.send(data);
		}
	}
}